#ifndef DICCTEST_H
#define DICCTEST_H

#include "DiccTrie.h"
#include <iostream>
#include <string>

/**
 * Esta clase realiza los test de unidad solamente del conjunto.
 * Se asume que las clases utilizadas funcionan correctame.
*/
class DiccTrieTest
{
	public:
        void StartTest (bool debug);
        void Result ();

	protected:
    	
		/** 
		 * Aca testeamos que dado un conjunto recien creado, no tenga elementos, y al 
		 * evaluar sobre elementos en el rango y fuera pertenece sea siempre falso.
		*/
	    bool dicctrieCrearVacio();
		bool definir();
		bool obtener();
		bool esClave();
	    bool claves();
		bool borrar();
		bool igualPorCopia();
		bool vacio();
		
	private:
        bool d; //usada para mostrar u ocultar los mensajes de error
		string test;
		string temp;
		int ok;
		int error;
		ConjString *conj;
		
		DiccTrie< int > *dicc;
		DiccTrie< int > *dicc2;
		DiccTrie< int > *dicc3;
		DiccTrie< DiccTrie<int> > dicc4;
		DiccTrie< DiccTrie<int> > dicc5;
};
void DiccTrieTest::StartTest(bool debug){
    //pongo la variable debug en el estado pedido
    this->d=debug;
	ok=0;
	error=0;
	if(this->dicctrieCrearVacio()){
		ok++;
	}else{
		error++;
	}

	if(this->definir()){
		ok++;
	}else{
		error++;
	}

	if(this->obtener()){
		ok++;
	}else{
		error++;
	}

	if(this->esClave()){
		ok++;
	}else{
		error++;
	}
	if(this->claves()){
		ok++;
	}else{
		error++;
	}
	if(this->borrar()){
		ok++;
	}else{
		error++;
	}
	if(this->igualPorCopia()){
		ok++;
	}else{
		error++;
	}
	delete dicc;
	delete dicc2;

}
void DiccTrieTest::Result (){
	cout << "DICCTRIE test Ok:" << ok << endl;
	cout << "DICCTRIE test error:" << error << endl;
};

bool DiccTrieTest::dicctrieCrearVacio(){
	if(d) cout << "DICC::CREARVacio:" << endl;
	
	if(d) cout << "DICC::creo dicc dicc2:" << endl;
	
	dicc = new DiccTrie<int> ();
	dicc2 = new DiccTrie<int> ();	

	if(d) cout << "DICC:: veo si se creo vacio:" << endl;

	if(!dicc->claves().vacio()){
		if(d) cout << "DICC::dicc tiene basura:" << endl;
		cout << "DICC::dicctrieCrearVacio:ERR(1)" << endl;
		return false;
	}
	if(!dicc2->claves().vacio()){
		if(d) cout << "DICC::dicc3 tiene basura:" << endl;
		cout << "DICC::dicctrieCrearVacio:ERR(2)" << endl;
		return false;
	}
    cout << "DICC::dicctrieCrearVacio:OK" << endl;
	return true;
}

bool DiccTrieTest::definir(){
	if(d) cout << endl << "DICC::DEFINIR:" << endl;

    //Test1 definir claves
    	if(d) cout << "DICC::definendo algunas claves:" << endl;
		//defino algunas claves
		dicc->definir("holasie",13);
        if(d)  cout << "holasie=>13" << endl;

		dicc->definir("h",25);
		if(d)  cout << "h=>25" << endl;

		dicc->definir("holgado",75);
		if(d)  cout << "holgado=>75" << endl << endl;

		if(d)  cout << "veo el dicc:" << endl << dicc << endl << endl;

		if(dicc->obtener("holasie")!=13){
           	cout << "DICC::definir:ERR(1)" << endl;
			return false;
		}else if(dicc->obtener("h")!=25){
      		cout << "DICC::definir:ERR(2)" << endl;
			return false;
		}else if(dicc->obtener("holgado")!=75){
   			cout << "DICC::definir:ERR(3)" << endl;
			return false;
		}

    //Test2 redefino
	    if(d)  cout << "DICC::DEFINIR de estructras mas complicadas: defino como significado un diccionario difinir('lala', dicc2)" <<endl ;
	    DiccTrie<int> *diccTemp;
		dicc4.definir("lala",*dicc2);
		dicc2->definir("alliasing",1);
		if(dicc4.obtener("lala").esClave("alliasing")){
			if(dicc4.obtener("lala").obtener("alliasing")==1){
                cout << "DICC::definir:ERR(4)" << endl;
				return false;
			}
		}

		if(d)  cout << "imprimo el resultado:" << endl;
		if(d)  cout << dicc4<< endl<<endl;

    //Test3 copiar )lo puse aca porque sino hay que rehacer toda la creacion del dicc2 en el otro test de igual por copia
    	if(d)  cout << "DICC:: dicc5 = dicc4:" << endl;
		dicc5=dicc4;
		if(&dicc5==&dicc4){
           	cout << "DICC::definir:ERR(5)" << endl;
			return false;
		}
		dicc2->definir("truchi",11);
		dicc5.definir("alliasing", *dicc2);
		if(d)  cout << "imprimo el dicc5:" << endl << dicc5 << endl << endl;
		if(dicc4.esClave("alliasing")){
           	cout << "DICC::definir:ERR(6)" << endl;
			return false;
		}
		
	//Test4: alliasing
	    if(d)  cout << "DICC::Prueba de aliassing: redefino una claves de dicc2 (el que esta como significado):" << endl;	
		if(d)  cout << "holgado=>11" << endl;
		
        dicc2->definir("holgado",11);
        
        if(d)  cout << "veo si cambio el dicc2:"  << endl << dicc2 << endl << endl;
		
        if(dicc4.obtener("lala").esClave("holgado")){	
			if(dicc4.obtener("lala").obtener("holgado")==11){
				if(d) cout << "ERROR: tiene aliasing" << endl << endl;
               	cout << "DICC::definir:ERR(7)" << endl;
				return false;
			}else{
				if(d)  cout << "GENIAL: no tiene aliasing"<< endl << endl;	
			}
		}
    cout << "DICC::definir:OK" << endl;
	return true;
}

bool DiccTrieTest::obtener(){
	//obtener
    if(d)  cout << "DICC::OBTENER:" << endl;
	int res,res2;
	res2 = dicc->obtener("holasie"); // esto deberia fallar
	if(res2==13){
		if(d)  cout << "obtiene funciono correctamente" << endl;
	}else{
		if(d)  cout << "obtiene NO FUNCION bien" << endl;
       	cout << "DICC::obtener:ERR" << endl;
		return false;
	}
	//res2 = dicc.obtener("noEncontrado"); // esto deberia fallar
	if(d)  cout << endl << endl;
    cout << "DICC::obtener:OK" << endl;
	return true;
}
bool DiccTrieTest::borrar(){
    if(d)  cout << "DICC::BORRAR:" << endl;
	int tam = dicc->claves().dameTamano(); 
	dicc->borrar("holgados");
	dicc->borrar("holga");
	if(tam != dicc->claves().dameTamano()){
       	if(d)  cout << "DICC::borrar:ERR(1)" << endl;
		return false;
	}
	if(d)  cout << endl << "borrar claves que no esten: (holgados, holga)" << endl;
	if(d)  cout << "veo como queda el diccionario:" << endl << dicc << endl << endl;
	
	dicc->borrar("holgado");
	if(dicc->esClave("holgado")){
       	if(d)  cout << "DICC::borrar:ERR(2)" << endl;
		return false;
	}
	if(d)  cout << endl << "borrar alguna clave que este: (holgado)" << endl;
	if(d)  cout << "veo como queda el diccionario:" << endl << dicc << endl << endl;
    cout << "DICC::borrar:OK" << endl;
	return true;

}

bool DiccTrieTest::esClave(){
	//esClave
    if(d)  cout << "DICC::ESCLAVE:y OBTENER" << endl;
	if(d)  cout << "test de esClave: " << endl;
	dicc->definir("holgado",33);
	if ( dicc->esClave("holgado") ){
		if(dicc->obtener("holgado") == 33){
			if(d)  cout << "funciona!!" << endl;
			if(d)  cout << "holgado es. " << dicc->obtener("holgado")	<< endl;
		}else{
			if(d)  cout << "holgado es. " << dicc->obtener("holgado") << " y deberia ser 33" << endl;
          	cout << "DICC::esClave:ERR(1)" << endl;
			return false;
		}
	}else{
		 if(d)  cout << "no anda el esclave";
         cout << "DICC::esClave:ERR(2)" << endl;
		 return false;
	}
   	cout << "DICC::esClave:OK" << endl;
	return true;
}

bool DiccTrieTest::claves(){
	ConjString esp;
    if(d)  cout << "DICC::CLAVES:" << endl;
	if(d)  cout << "obtengo el conjunto de claves y las imprimo:" << endl;
	if(d)  cout << dicc->claves() << endl << endl;
	esp = dicc->claves();
	
	IteradorConjString it(esp);
	while (it.tieneProximo()) {
		if(!dicc->esClave(it.proximo())){
          	cout << "DICC::claves:ERR" << endl;
			return false;
		}
	}
  	cout << "DICC::claves:OK" << endl;
	return true;

	//borrar

}
bool DiccTrieTest::igualPorCopia(){
	int tam=0;
	if(d)  cout << endl << "DICC::COPIA1:" << endl;
	dicc->definir("holgado",10000);
    //Test1 copiar
    	if(d)  cout << "DICC:: dicc2 = dicc:" << dicc->claves() << endl << dicc2->claves()<< endl<<endl;
		tam = dicc->claves().dameTamano();

		*dicc2=*dicc;
		if(d)  cout << "veo el dicc:" << endl << dicc->claves() << endl << endl;
		if(d)  cout << "veo el dicc2:" << endl << dicc2->claves() << endl << endl;
		if(tam != dicc2->claves().dameTamano()){
			if(d)  cout << "ERROR: la cantidad de claves no es la correcta" << endl << endl;
            cout << "DICC::igualPorCopia:ERR(1)" << endl;
			return false;
		}
    //Test2 alliasing
    	if(d)  cout << "DICC::Prueba de aliassing: redefino una claves:" << endl;	
		if(d)  cout << "holgado=>1" << endl;
		dicc->definir("holgado",1);
        //si dicc2 tiene definida holgado es porque hay alliasing
		if(dicc2->esClave("holgado")){	
			if(dicc2->obtener("holgado")==1){
	   			if(d)  cout << "ERROR: tiene aliasing" << endl << endl;
              	cout << "DICC::igualPorCopia:ERR(2)" << endl;
				return false;
			}else
				if(d)  cout << "GENIAL: no tiene aliasing"<< endl << endl;	
		}else{
          	if(d)  cout << "DICC::igualPorCopia:OK" << endl;
          	if(d)  cout << "DICC::no hay aliasing" << endl;
		}
	//Test3 dicc=dicc
    	if(d)  cout << "DICC: copio sobre si mismo dicc=dicc" << endl << endl;
		tam = dicc->claves().dameTamano();
		dicc = dicc;
		if(d)  cout << "vemos como queda" << endl << dicc << endl << endl;
		if(tam != dicc->claves().dameTamano()){
           	cout << "DICC::igualPorCopia:ERR(3)" << endl;
			return false;
		}

	//Test5: copiar sobre si mismo
    	if(d)  cout << "DICC: copio sobre si mismo dicc4=dicc4" << endl << endl;
		dicc = dicc;
		if(d)  cout << "vemos como queda" << endl << dicc << endl << endl;
		if(dicc->claves().vacio()){
           	cout << "DICC::igualPorCopia:ERR(4)" << endl;
			return false;
		}
      	cout << "DICC::igualPorCopia:OK" << endl;
	return true;
}

#endif
